package org.wmq.positiontoshop.controller;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.wmq.positiontoshop.common.LocalCache;
import org.wmq.positiontoshop.common.MinioClient;
import org.wmq.positiontoshop.common.Result;
import org.wmq.positiontoshop.config.ApplicationConfiguration;
import org.wmq.positiontoshop.model.DO.User;
import org.wmq.positiontoshop.service.BloomFilterService;
import org.wmq.positiontoshop.service.UserService;

import java.util.Random;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {
    @Autowired
    private UserService userService;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private MinioClient minioClient;
    @Autowired
    private LocalCache localCache;
    @Autowired
    private KafkaTemplate<String,String> kafkaTemplate;
    @Autowired
    private BloomFilterService bloomFilterService;
    @Autowired
    private ApplicationConfiguration applicationConfiguration;
    @Autowired
    private Random random;

    @GetMapping("/{id}")
    public Result<User>  getUserById(@PathVariable Long id){
        String userJson = this.localCache.get("user:" + id);
        if (userJson != null){
            return Result.success(JSON.parseObject(userJson, User.class));
        }
        userJson = this.redisTemplate.opsForValue().get("user:" + id);
        if (userJson != null){
            this.localCache.put("user:" + id, userJson);
            return Result.success(JSON.parseObject(userJson, User.class));
        }
        User user = this.userService.getById(id);
        if (user == null){
            log.info("user not found, id={}",id);
            return Result.error("USER_NOT_FOUND");
        }
        userJson = JSON.toJSONString(user);
        this.localCache.put("user:" + id, userJson);
        this.redisTemplate.opsForValue().set("user:" + id, userJson,6000 + ThreadLocalRandom.current().nextInt(1000), TimeUnit.MILLISECONDS);
        return Result.success(user);
    }

    @PostMapping
    public Result<User> createUser(@RequestBody User user){
        boolean saved = this.userService.save(user);
        if (!saved){
            log.info("create user failed, user={}",user);
            return Result.error("CREATE_USER_FAILED");
        }
        return Result.success(user);
    }

    @PutMapping
    public Result<User> updateUser(@RequestBody User user){
        boolean updated = this.userService.updateById(user);
        if (!updated){
            log.info("update user failed, user={}",user);
            return Result.error("UPDATE_USER_FAILED");
        }
        String key = "user:" + user.getId();
        this.localCache.remove(key);
        this.redisTemplate.delete(key);
        this.kafkaTemplate.send("user.update",key);
        return Result.success(user);
    }

    @DeleteMapping("/{id}")
    public Result<Void> deleteUser(@PathVariable Long id){
        boolean deleted = this.userService.removeById(id);
        if (!deleted){
            log.info("delete user failed, id={}",id);
            return Result.error("DELETE_USER_FAILED");
        }
        String key = "user:" + id;
        this.localCache.remove(key);
        this.redisTemplate.delete(key);
        this.kafkaTemplate.send("user.update",key);
        return Result.success();
    }

    @PutMapping("/{id}")
    public Result<Void> updateUserAvatar(@PathVariable Long id, @RequestParam MultipartFile avatar) throws Exception {
        if (avatar.isEmpty()) {
            log.info("update user avatar failed, id={}, because avatar is empty",id);
            return Result.error("AVATAR_IS_EMPTY");
        }
        User user = this.userService.getById(id);
        if (user == null) {
            log.info("update user avatar failed, id={}, because user not exists",id);
            return Result.error("USER_NOT_EXISTS");
        }
        if (user.getAvatarUrl() != null) {
            this.minioClient.deleteObject(this.applicationConfiguration.getUserAvatarBucket(),user.getAvatarUrl());
        }
        String avatarUrl = UUID.randomUUID().toString();
        this.minioClient.uploadObject(this.applicationConfiguration.getUserAvatarBucket(), avatarUrl, avatar.getInputStream(), avatar.getSize(), avatar.getContentType());
        boolean update = this.userService.lambdaUpdate().eq(User::getId, id).set(User::getAvatarUrl, avatarUrl).update();
        if (update){
            log.info("update user avatar success, id={}, avatarUrl={}",id,avatarUrl);
            return Result.success();
        }else{
            log.error("update user avatar failed, id={}, avatarUrl={}, because update user failed",id,avatarUrl);
            return Result.error("UPDATE_USER_AVATAR_FAILED");
        }
    }
}
